<?php

namespace july\julyadmin\builder\forms;

use july\julyadmin\builder\FormBase;

/**
 * 表单Select组件
 */
class Select extends FormBase
{
    /**
     * 添加组件
     * @Author
     * @DateTime 2023-07-16T12:14:26+0800
     * @param    string                   $field 字段
     * @param    string                   $label 名称
     * @return this
     */
    public function __construct($field = '', $label = '')
    {
        $form              = new \stdClass();
        $form->type        = 'select';
        $form->field       = $field;
        $form->label       = $label;
        $form->placeholder = "请选择" . $label;
        $form->help        = '';
        $form->tips        = ['tips' => '', 'direction' => 2, 'time' => 0, 'background' => '#000000'];
        $form->required    = false;
        $form->style       = '';
        //内容
        $form->value   = '';
        $form->default = '';
        //轩重工后显示的下一个组件
        $form->withNextForm = null;

        //select下拉数据
        $form->options = [];
        //ajax获取数据url,当options为空生效
        $form->dataUrl = '';
        //ajax获取数据每页多少条
        $form->rows = 10;
        //是否多选
        $form->multiple = false;
        //是否被关联
        $form->isWith = false;
        //是否显示label
        $form->showLabel = true;
        //父组件id
        $form->parent_id = '';
        //要关联显示的表单组件列表
        $form->whenForms = [];
        //要关联显示的条件
        $form->whenWhere = '';
        $this->form      = $form;
        return $this;
    }

    /**
     * 设置是否被关联
     * @Author
     * @DateTime 2023-07-16T12:43:03+0800
     * @param    boolean                  $isWith 是否被关联,true,false
     */
    public function setIsWith($isWith = true)
    {
        $this->form->isWith = $isWith;
        return $this;
    }

    /**
     * 设置父组件id，当被关联显示的时候，会带上父组件的值，作为查询条件
     * @Author
     * @DateTime 2023-07-16T12:42:44+0800
     * @param    string                   $parent_id 父组件id
     */
    public function setParentId($parent_id = '')
    {
        $this->form->parent_id = $parent_id;
        return $this;
    }

    /**
     * 是否显示label
     * @Author
     * @DateTime 2023-07-16T12:42:08+0800
     * @param    boolean                  $show 是否显示label,true,false
     * @return   this
     */
    public function showLabel($show = true)
    {
        $this->form->showLabel = $show;
        return $this;
    }

    /**
     * 关联在后面显示的组件
     * @Author
     * @DateTime 2023-07-16T12:43:21+0800
     * @param    form                   $formObject 要关联显示的下一个组件
     * @return   this
     */
    public function withNext($formObject)
    {
        if ($formObject instanceof \Closure) {
            $builder = new \july\julyadmin\builder\builder();
            $form    = new \july\julyadmin\builder\Form($builder);
            $formObject($form);
            if (count($form->forms)) {
                foreach ($form->forms as $form_key => $form_val) {
                    $form->forms[$form_key]->setData($this->data)->isView($this->isView);
                }
                $this->form->withNextForm = $form->forms;
            }
        }
        return $this;
    }

    /**
     * 设置style
     * @Author
     * @DateTime 2023-07-16T12:19:05+0800
     * @param    string                   $style 样式，直接写css
     * @return   this
     */
    public function style($style = '')
    {
        $this->form->style = $style;
        return $this;
    }

    /**
     * 设置下拉每页条数
     * @Author
     * @DateTime 2023-07-16T12:32:42+0800
     * @param    integer                  $total 每页条数
     */
    public function rows($total = 10)
    {
        $this->form->rows = $total;
        return $this;
    }

    /**
     * 设置下拉列表请求地址
     * @Author
     * @DateTime 2023-07-16T12:32:12+0800
     * @param    string                   $url 请求地址
     * @return   this
     */
    public function dataUrl($url = "")
    {
        $this->form->dataUrl = is_string($url) ? $url : (string) $url;
        return $this;
    }

    /**
     * 设置select 数据
     * @Author
     * @DateTime 2023-07-16T12:25:21+0800
     * @param    array                   $options 下拉数据，键值对数组
     * @return   this
     */
    public function options($options = [])
    {

        $this->form->options = $options;
        return $this;
    }

    /**
     * 设置是否多选
     * @Author
     * @DateTime 2023-07-16T12:30:15+0800
     * @param    boolean                  $multiple 是否多选,true,false
     * @return   this
     */
    public function multiple($multiple = true)
    {
        $this->form->multiple = $multiple;
        return $this;
    }

    /**
     * 检查一个数组是否是一维数组，如果是则返回true，否则返回false
     * @Author   July
     * @DateTime 2023-11-18T17:15:52+0800
     * @param    array                    $array 要检查的数组
     * @return   boolean                         如果是则返回true，否则返回false
     */
    private function isOneDimensionalArray($array = [])
    {
        foreach ($array as $value) {
            if (is_array($value)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 关联显示指定组件
     * @Author
     * @DateTime 2023-07-16T12:43:21+0800
     * @param    string                   $where  只能是：一维数组,数字,字符串类型，如:'1'或者1或者[1,2]，如果为数组，将判断当前组件的值是否存在于数组中'注意：区分数据类型'
     * @param    form                     $form   要关联显示的下一个组件
     * @return   this
     */
    public function when($where = '', ...$form)
    {
        if (!is_array($where) && !is_numeric($where) && !is_string($where)) {
            throw new \Exception("第一个参数是显示条件，只能是：一维数组,数字,字符串类型，如:'1'或者1或者[1,2]，如果为数组，将判断当前组件的值是否存在于数组中'注意：区分数据类型'");
        }
        if (!is_array($form)) {
            throw new \Exception("第二个参数必须是july\julyadmin\builder\form");
        }
        $this->form->whenWhere = $where;
        $this->form->whenForms = $form;
        return $this;
    }

    /**
     * 渲染组件
     * @Author
     * @DateTime 2023-07-16T12:22:46+0800
     * @return   array
     */
    public function render($items_field = '')
    {
        if ($items_field) {
            $this->html        = '';
            $this->script      = '';
            $this->form->value = '';
        }
        $this->form->value = $this->form->default;
        if (isset($this->data[$this->form->field]) && $this->data[$this->form->field] !== "") {
            $this->form->value = $this->data[$this->form->field];
        }

        $values = explode(',', $this->form->value);
        foreach ($values as $vk => $vv) {
            $values[$vk] = $vv;
        }
        $this->form->value = json_encode(array_filter($values, function ($value) {
            return $value !== null; // 自定义过滤条件
        }));

        $required_html = $this->form->required && !$this->isView ? ' <font style="color:red;font-weight:bold;font-size:20px;vertical-align:-webkit-baseline-middle;">*</font>' : '';

        //处理tips
        $tips = '';
        if ($this->form->tips['tips']) {
            $tips = '<font class="form-tips-icon"><i class="mdi mdi-information-outline" tips="' . $this->form->tips['tips'] . '" direction="' . $this->form->tips['direction'] . '" time="' . $this->form->tips['time'] . '" background="' . $this->form->tips['background'] . '" onclick="showTips(this)"></i></font>';
        }

        $colWidth = $this->colWidth ? 'col-md-' . $this->colWidth : '';
        if (!$this->form->parent_id) {
            $mt = ' mt-3 ';
            $mb = ' mb-3 ';
        } else {
            $mt = '';
            $mb = '';
        }
        $this->html .= <<< EOT

        <div class="row ps-0 pe-0 ms-0 me-0{$mt}{$mb} {$colWidth}">
EOT;
        if ($this->form->showLabel == true) {
            $this->html .= <<<EOT

            <label class="col-sm-{$this->labelWidth} col-form-label pe-2 col-form-label-sm text-sm-end text-md-end text-lg-end text-xl-end">
                {$tips}{$this->form->label}
                {$required_html}
            </label>

EOT;
        }

        // 处理when开始
        $whenScript = '';
        foreach ($this->form->whenForms as $form_k => $form_v) {
            //如果条件是一维数组
            if (is_array($this->form->whenWhere)) {
                $whereStr = json_encode($this->form->whenWhere, JSON_UNESCAPED_UNICODE);
                $whenScript .= <<<EOT

                var is_show = false;
                if(val instanceof Array){
                    {$whereStr}.map((item,index)=>{
                        if(val.includes(item) || val.includes(item.toString())){
                            is_show = true;
                        }
                    });
                }else{
                    if({$whereStr}.includes(val) || {$whereStr}.includes(Number(val))){
                        is_show = true;
                    }
                }
                if(is_show){
                    $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().show();
                }else{
                    $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().hide();
                }

EOT;
            }

            //如果是字符串
            if (is_string($this->form->whenWhere)) {
                $whenScript .= <<<EOT

                if(val instanceof Array){
                    if(val.includes('{$this->form->whenWhere}')){
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().show();
                    }else{
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().hide();
                    }
                }else{
                    if('{$this->form->whenWhere}'==val){
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().show();
                    }else{
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().hide();
                    }
                }

EOT;
            }

            //如果是数字
            if (is_numeric($this->form->whenWhere)) {
                $whenScript .= <<<EOT

                if(val instanceof Array){
                    if(val.includes({$this->form->whenWhere}) || val.includes('{$this->form->whenWhere}')){
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().show();
                    }else{
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().hide();
                    }
                }else{
                    if({$this->form->whenWhere}==val || '{$this->form->whenWhere}'==val){
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().show();
                    }else{
                        $('[name="{$this->items_row_prefix}{$form_v->form->field}"]').parent().parent().hide();
                    }
                }

EOT;
            }
        }

        if (!$this->form->whenWhere || !$this->form->whenForms) {
            $whenScript = '';
        }
        //处理when结束

        $input_html = "";

        //如果是禁止状态，输出一个font，用来记录值
        if ($this->isView) {
            $input_html .= '';
        }
        //处理select2组件
        $required             = $this->form->required ? 'required' : '';
        $multiple             = $this->form->multiple === true || $this->form->multiple === 'true' ? 'multiple="multiple"' : '';
        $is_multiple          = $this->form->multiple === true || $this->form->multiple === 'true' ? '[]' : '';
        $this->form->multiple = $this->form->multiple === true || $this->form->multiple === 'true' ? 'true' : 'false';
        $is_hide              = $this->isView ? 'display:none;' : '';
        $colPaddingClearStyle = $this->form->isWith ? 'padding:0px;' : '';
        $input_html .= <<< EOT

                <div style="{$this->form->style}">
                    <div class="row">
                        <div class="col" style="{$colPaddingClearStyle}">
                            <font class="d-flex align-items-center h-100 d-none">
                                <font style="float:left;" class="form-select-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}-view-value col-form-label pe-2 col-form-label-sm text-sm-end text-md-end text-lg-end text-xl-end"></font>
                            </font>
                            <div style="{$is_hide}">
                                <select class="form-control select2" {$required} id="form-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}" name="{$this->items_row_prefix}{$this->form->field}{$is_multiple}">
                                </select>
                                <div class="error-box"></div>
                            </div>
                        </div>

EOT;
        if ($this->form->withNextForm) {
            foreach ($this->form->withNextForm as $fk => $fv) {
                if (!$fv->form->parent_id) {
                    throw new \Exception("被关联的组件没有设置父组件id，获取下拉数据时需要传递父组件值到后台查询，请调用setParentId()传递一个值，比如父组件字段是role_id，那么这里就填写role_id");
                }
                $res   = $fv->setData($this->data)->setItemsField($this->items_field)->isView($this->isView)->setColWidth(12)->setIsWith(true)->render($items_field);
                $field = md5($items_field . $fv->form->field) . $this->items_row_id_template_fun;
                $input_html .= <<<EOT

                        <div class="col pr-0">
                            {$res['html']}
                            {$res['script']}
                            <script>
                                initialize{$field}();
                                $('#form-{$items_field}{$fv->form->parent_id}{$this->items_row_id_template_fun}').on('select2:select',function(){
                                    initialize{$field}();
                                    setTimeout(function(){
                                        formValidate();
                                    },200);
                                });
                            </script>
                        </div>

EOT;
            }
        }
        $input_html .= <<<EOT

                    </div>
                </div>

EOT;
        $field    = md5($items_field . $this->form->field) . $this->items_row_id_template_fun;
        $disabled = $this->readonly ? 'true' : 'false';
        $this->script .= <<<EOT

            <script>
                function initialize{$field}(){
                    //这里要做判断，如果是要放到items组件的话这里必须要写，不然放在items中会出现两个
                    var field = '{$field}';
                    if(field.indexOf('_____')>-1){
                        return false;
                    }


                    //处理select2组件
                    $('#form-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}').select2({
                        //指定语言为中文，国际化才起效
                        language : "zh-CN",
                        multiple :{$this->form->multiple},
                        allowClear:true,
                        closeOnSelect:!{$this->form->multiple},
                        placeholder:'{$this->form->placeholder}',
                        placeholderOption:"first",
                        disabled:{$disabled},
EOT;
        if ($this->form->dataUrl) {
            $this->script .= <<<EOT

                        ajax : {
                            url : '{$this->form->dataUrl}',
                            dataType : 'json',
                            //延迟显示
                            delay:50,
                            data:function(params) {
                                return {
                                    //搜索框内输入的内容，传递到后端的parameter为keyword
                                    keyword:params.term,
                                    parent_id:$('#form-{$items_field}{$this->form->parent_id}{$this->items_row_id_template_fun}').val() instanceof Array?$('#form-{$items_field}{$this->form->parent_id}{$this->items_row_id_template_fun}').val().join(','):$('#form-{$items_field}{$this->form->parent_id}{$this->items_row_id_template_fun}').val(),
                                    //第几页
                                    page:params.page,
                                    //每页显示多少行
                                    rows:{$this->form->rows}
                                };
                            },
                            //分页
                            processResults : function(data, params) {
                                params.page = params.page || 1;
                                return {
                                    //后台返回的数据集
                                    results : data.data,
                                    pagination : {
                                        //总页数为10，那么1-9页的时候都可以下拉刷新
                                        more : params.page < Math.ceil(data.total/{$this->form->rows})
                                    }
                                };
                            },
                            cache : false,
                        },
                        escapeMarkup : function(markup) {
                            return markup;
                        },
EOT;
        } else {
            $data = [];
            if ($this->isOneDimensionalArray($this->form->options)) {
                foreach ($this->form->options as $ok => $ov) {
                    $data[] = ['id' => $ok, 'text' => $ov];
                }
            } else {
                foreach ($this->form->options as $ok => $ov) {
                    if (!isset($ov['id'])) {
                        throw new \Exception("数组为包含id字段");
                    }
                    if (!isset($ov['text'])) {
                        throw new \Exception("数组为包含text字段");
                    }
                    $data[] = ['id' => $ov['id'], 'text' => $ov['text'], 'disabled' => isset($ov['disabled']) ? $ov['disabled'] : false];
                }
            }

            $data = json_encode($data);
            $this->script .= <<<EOT
                        data:{$data},
EOT;
        }
        $this->script .= <<<EOT

                        templateSelection : function(repo) {
                            //列表中选择某一项后显示到文本框的内容

EOT;
        if ($this->isView) {
            $this->script .= <<<EOT
                        var value_box = $(".form-select-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}-view-value");
                        $(".form-select-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}-view-value").parent().addClass('d-block').removeClass('d-none');
                        var val = value_box.html();

                        if(repo.id){
                            if(val && !['空','加载中'].includes(val)){
                                val = val+','+repo.text;
                            }else{
                                val = repo.text;
                            }
                            var arr = val.split(',');
                            var list = [];
                            val = arr.filter((item) => !list.includes(item.name) && list.push(item.name));
                            val = val.join(',');
                            value_box.html(val);
                        }else{
                            value_box.html('空');
                        }

EOT;
        }
        $this->script .= <<<EOT

                            return repo.text;
                        }
                    }).on('select2:open', function(e) {
                        //展开时搜索框获取焦点
                        const selectId = e.target.id;
                        setTimeout(function(){
                            $(".select2-search__field[aria-controls='select2-"+selectId+"-results']").each(function (key,value,){
                                value.focus();
                            });
                        },100);
                    }).on('change', function(e) {
                        var val = $('#form-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}').select2("val");

                        {$whenScript}

                    });;

EOT;
        if ($this->form->dataUrl) {
            if ($this->form->parent_id && isset($this->data[$this->form->parent_id])) {
                $parent_value = json_encode($this->data[$this->form->parent_id]);
            } else {
                $parent_value = json_encode([]);
            }
            $this->script .= <<<EOT
                    //如果有默认值，那么加载出来，并且选择上
                    if({$this->form->value}){
                        var that = this;
                        $(".form-select-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}-view-value").html('加载中');
                        window.loading  = layer.load(2, { shade: false});
                        $.ajax({
                            type:'GET',
                            url:'{$this->form->dataUrl}',
                            data:{default:{$this->form->value},parent_id:{$parent_value}},
                            dataType:'json',
                            success:function(res) {
                                layer.close(window.loading);
                                if(res.hasOwnProperty("data")){
                                    res.data.map((select_data_item,select_data_index)=>{
                                        $("#form-"+'{$items_field}{$this->form->field}{$this->items_row_id_template_fun}').append('<option selected value="' + select_data_item.id + '">' + select_data_item.text + '</option>');
                                    });
                                    //这里一定要验证一遍，否则验证错误提示很有可能跑到select2上面
                                    setTimeout(function(){
                                        formValidate();
                                    },200);
                                    $('#form').valid();
                                    $('#form-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}').val({$this->form->value}).trigger("change");
                                } else {
                                    $(".form-select-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}-view-value").html('数据加载失败');
                                }
                            },
                            error:function(res){
                                layer.close(window.loading);
                                $(".form-select-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}-view-value").html('数据加载失败'+JSON.stringify(res));
                            }
                        });
                    }

EOT;
        } else {
            if ($this->form->multiple) {
                $this->script .= <<<EOT

                            $('#form-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}').val([{$this->form->value}]).trigger('change');

EOT;
            }
        }

        if ($this->isView) {
            $this->script .= <<<EOT

                        $('#form-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}').prop('disabled', true);
                        $('.select2-selection').css('background','unset');
EOT;
        }
        $this->script .= <<<EOT

                    $('#form-{$items_field}{$this->form->field}{$this->items_row_id_template_fun}').on("change", function(e) {
                        $("#form").valid();
                    })
                }
                setTimeout(function(){
                    formValidate();
                },200);

            </script>

EOT;

        if (!$this->form->isWith) {
            $this->script .= <<<EOT

            <script>
                initialize{$field}();
            </script>

EOT;
        }

        //处理help
        if ($this->form->help && !$this->isView) {
            $input_html .= <<<EOT

            <div class="form-help form-text">
                <i class="mdi mdi-information-outline"></i>
                <font>{$this->form->help}</font>
            </div>
EOT;
        }

        $class = $this->inputWidth ? 'col-sm-' . $this->inputWidth : '';
        $this->html .= <<< EOT

            <div class="{$class}">
                {$input_html}
            </div>
        </div>

EOT;

        $result = ['html' => $this->html, 'script' => $this->script];
        return $result;
    }
}
